﻿using System;
using System.Linq;
using MigraDoc.DocumentObjectModel;
using MigraDoc.DocumentObjectModel.Tables;
using MigraDoc.Rendering;
using PdfSharp.Pdf;
using Xenta.Entities;
using Xenta.Enums;
using Xenta.Utils;

namespace Xenta.Operations
{
    public class OrderPdfReport : ReportOperation
    {
        #region Properties

        public override string MimeType
        {
            get
            {
                return "application/pdf";
            }
        }

        #endregion

        #region Utilities

        protected override Err Validate(IUnitOfWork uow)
        {
            if(Properties == null)
                return Err.Of(this).NotValid("Properties");
            if(!Properties.ContainsKey("orderID"))
                return Err.Of(this).NotSpecified("orderID");
            return base.Validate(uow);
        }

        protected override void Report(IUnitOfWork uow)
        {
            int orderID = Properties["orderID"].ParseAs<Int32>();
            var order = uow.Execute(new GetOrder
            {
                ThrowsException = true,
                EntityID = orderID
            }).Result;
            var customer = order.Customer;
            var customerAcc = customer.Account;
            var localization = customerAcc.LocalizationProfile;
            var sysLocalization = uow.Execute(new GetLocalizationProfileByCode
            {
                ThrowsException = true,
                Code = uow.Execute(new GetConfigParamValueByKey
                {
                    Key = Par.In("Core").Of<LocalizationProfileEntity>().Name("System")
                }).Result
            }).Result;

            string locale = Properties.ContainsKey("locale")
                ? Properties["locale"]
                : String.Empty;
            if(!String.IsNullOrWhiteSpace(locale))
            {
                var tmp = uow.Execute(new GetLocalizationProfileByCode
                {
                    ThrowsException = true,
                    Code = locale
                }).Result;
                if(tmp != null)
                    localization = tmp;
            }

            var languagPack = uow.Execute(new GetLanguagePackContentByCode
            {
                Code = "PdfOrder",
                LanguageID = localization.Language.EntityID
            }).Result;
            if(languagPack == null)
                throw Err.Of(this).NotFound("LanguagePack").Ex();

            int utcOffset = localization.TimeZone.UtcOffset;
            string dtFmt = localization.Country.DateTimeFormat;
            var priceFmt = sysLocalization.Currency.PriceFormat;
            var numFmt = localization.Country.NumericFormat;
            var dtNow = DateTime.UtcNow;

            var doc = new Document
            {
                Info =
                {
                    Title = String.Format(languagPack["Report.Title"], order.EntityID, order.Guid),
                    Author = languagPack["Report.Author"],
                    Comment = languagPack["Report.Comment"],
                    Subject = languagPack["Report.Subject"]
                }
            };
            var sec = doc.AddSection();

            #region PDF

            #region Title

            sec.AddParagraph().AddText(TextFormat.Bold, doc.Info.Title);
            sec.AddParagraph();
            sec.AddParagraph();

            #endregion

            #region Head

            var tblTop = new Table
            {
                Borders =
                {
                    Width = Unit.Zero,
                },
                Format =
                {
                    Font =
                    {
                        Size = Unit.FromPoint(9)
                    }
                }
            };
            {
                tblTop.AddColumn(Unit.FromCentimeter(8));
                tblTop.AddColumn(Unit.FromCentimeter(8));

                var row = new Row();
                {
                    var cell0 = row.Cells[0];
                    {
                        var p = new Paragraph();
                        {
                            var addr = order.SellerAddress;
                            p.AddFmtText(TextFormat.Bold, languagPack["Report.Order.SellerAddress"], addr.EntityName);
                            p.AddLineBreak();
                            p.AddLineBreak();
                            p.AddText(addr.ContactName);
                            p.AddLineBreak();
                            p.AddFmtText("{0} {1}", addr.Address1, addr.Address2);
                            p.AddLineBreak();
                            p.AddFmtText("{0}, {1} {2}", addr.City, addr.Region.Name, addr.PostalCode);
                            p.AddLineBreak();
                            p.AddText(addr.Country.Name);
                            p.AddLineBreak();
                            if(!String.IsNullOrWhiteSpace(addr.PhoneNumber))
                            {
                                p.AddFmtText("T: {0}", addr.PhoneNumber);
                                p.AddLineBreak();
                            }
                            if(!String.IsNullOrWhiteSpace(addr.FaxNumber))
                            {
                                p.AddFmtText("F: {0}", addr.FaxNumber);
                                p.AddLineBreak();
                            }
                            if(!String.IsNullOrWhiteSpace(addr.Website))
                            {
                                p.AddFmtText("W: {0}", addr.Website);
                                p.AddLineBreak();
                            }
                            p.AddFmtText("@: {0}", addr.Email);
                        }
                        cell0.Add(p);
                    }
                    var cell1 = row.Cells[1];
                    {
                        var p = new Paragraph
                        {
                            Format =
                            {
                                Alignment = ParagraphAlignment.Right
                            }
                        };
                        {
                            p.AddFmtText(TextFormat.Italic, languagPack["Report.Order.Identifier"], order.EntityID, order.Guid);
                            p.AddLineBreak();
                            p.AddFmtText(TextFormat.Italic, languagPack["Report.Order.CreatedOn"], order.CreatedOn.ToLocal(utcOffset).ToStringByFmt(dtFmt));
                            p.AddLineBreak();
                            p.AddLineBreak();
                            p.AddText(TextFormat.Bold, languagPack["Report.Order.Status"]);
                            p.AddText(FlagsHelper.G1_Flags(order.Flags).ToString());
                            p.AddLineBreak();
                            p.AddText(TextFormat.Bold, languagPack["Report.Order.Total"]);
                            p.AddFmtText(priceFmt, numFmt.Convert(order.Total));
                            p.AddLineBreak();
                            p.AddLineBreak();
                            p.AddText(TextFormat.Bold, languagPack["Report.Order.TaxAmount"]);
                            p.AddFmtText(priceFmt, numFmt.Convert(order.TaxAmount));
                            p.AddLineBreak();
                            p.AddText(TextFormat.Bold, languagPack["Report.Order.DiscountAmount"]);
                            p.AddFmtText(priceFmt, numFmt.Convert(order.DiscountAmount));
                            p.AddLineBreak();
                            p.AddText(TextFormat.Bold, languagPack["Report.Order.HandlingFee"]);
                            p.AddFmtText(priceFmt, numFmt.Convert(order.HandlingFee));
                            p.AddLineBreak();
                            p.AddText(TextFormat.Bold, languagPack["Report.Order.ShippingPrice"]);
                            p.AddFmtText(priceFmt, numFmt.Convert(order.ShippingPrice));
                            p.AddLineBreak();
                            p.AddText(TextFormat.Bold, languagPack["Report.Order.Subtotal"]);
                            p.AddFmtText(priceFmt, numFmt.Convert(order.Subtotal));
                        }
                        cell1.Add(p);
                    }
                }
                tblTop.Rows.Add(row);
                sec.AddParagraph();
            }
            sec.Add(tblTop);
            sec.AddParagraph();

            #endregion

            #region Addresses

            var tblAddr = new Table
            {
                Borders =
                {
                    Color = PDFHelper.COLOR_BLACK,
                    Width = Unit.FromCentimeter(0.01),
                    Style = BorderStyle.Single,
                },
                TopPadding = Unit.FromCentimeter(0.05),
                BottomPadding = Unit.FromCentimeter(0.05)
            };
            {
                tblAddr.AddColumn(Unit.FromCentimeter(8));
                tblAddr.AddColumn(Unit.FromCentimeter(8));

                var rowHeader = new Row
                {
                    HeadingFormat = true,
                    Format =
                    {
                        Font =
                        {
                            Bold = true
                        },
                        Alignment = ParagraphAlignment.Left
                    }
                };
                {
                    rowHeader.Cells[0].AddParagraph().AddFmtText(languagPack["Report.Order.BillingAddress"], order.BillingAddress.ContactName);
                    rowHeader.Cells[1].AddParagraph().AddFmtText(languagPack["Report.Order.ShippingAddress"], order.ShippingAddress.ContactName);
                }
                tblAddr.Rows.Add(rowHeader);

                var row = new Row();
                {
                    var cell0 = row.Cells[0];
                    {
                        var p = new Paragraph();
                        {
                            var addr = order.BillingAddress;
                            p.AddText(addr.ContactName);
                            p.AddLineBreak();
                            p.AddFmtText("{0} {1}", addr.Address1, addr.Address2);
                            p.AddLineBreak();
                            p.AddFmtText("{0}, {1} {2}", addr.City, addr.Region.Name, addr.PostalCode);
                            p.AddLineBreak();
                            p.AddText(addr.Country.Name);
                            p.AddLineBreak();
                            if(!String.IsNullOrWhiteSpace(addr.PhoneNumber))
                            {
                                p.AddFmtText("T: {0}", addr.PhoneNumber);
                                p.AddLineBreak();
                            }
                            if(!String.IsNullOrWhiteSpace(addr.FaxNumber))
                            {
                                p.AddFmtText("F: {0}", addr.FaxNumber);
                                p.AddLineBreak();
                            }
                            p.AddFmtText("@: {0}", addr.Email);
                        }
                        cell0.Add(p);
                    }
                    var cell1 = row.Cells[1];
                    {
                        var p = new Paragraph();
                        {
                            var addr = order.ShippingAddress;
                            p.AddText(addr.ContactName);
                            p.AddLineBreak();
                            p.AddFmtText("{0} {1}", addr.Address1, addr.Address2);
                            p.AddLineBreak();
                            p.AddFmtText("{0}, {1} {2}", addr.City, addr.Region.Name, addr.PostalCode);
                            p.AddLineBreak();
                            p.AddText(addr.Country.Name);
                            p.AddLineBreak();
                            if(!String.IsNullOrWhiteSpace(addr.PhoneNumber))
                            {
                                p.AddFmtText("T: {0}", addr.PhoneNumber);
                                p.AddLineBreak();
                            }
                            if(!String.IsNullOrWhiteSpace(addr.FaxNumber))
                            {
                                p.AddFmtText("F: {0}", addr.FaxNumber);
                                p.AddLineBreak();
                            }
                            p.AddFmtText("@: {0}", addr.Email);
                        }
                        cell1.Add(p);
                    }
                }
                tblAddr.Rows.Add(row);
            }
            sec.Add(tblAddr);
            sec.AddParagraph();

            #endregion

            #region Items

            var tblItems = new Table
            {
                Borders =
                {
                    Color = PDFHelper.COLOR_BLACK,
                    Width = Unit.FromCentimeter(0.01),
                    Style = BorderStyle.Single
                },
                TopPadding = Unit.FromCentimeter(0.05),
                BottomPadding = Unit.FromCentimeter(0.05)
            };
            {
                tblItems.AddColumn(Unit.FromCentimeter(5));
                tblItems.AddColumn(Unit.FromCentimeter(4));
                tblItems.AddColumn(Unit.FromCentimeter(3));
                tblItems.AddColumn(Unit.FromCentimeter(4));

                var rowTitle = new Row
                {
                    HeadingFormat = true,
                    Format =
                    {
                        Font =
                        {
                            Bold = true
                        },
                        Alignment = ParagraphAlignment.Center
                    }
                };
                {
                    var cell0 = rowTitle.Cells[0];
                    cell0.MergeRight = 3;
                    cell0.AddParagraph(languagPack["Report.Order.Items"]);
                }
                tblItems.Rows.Add(rowTitle);

                var rowHeader = new Row
                {
                    HeadingFormat = true,
                    Format =
                    {
                        Font =
                        {
                            Bold = true
                        },
                        Alignment = ParagraphAlignment.Center
                    }
                };
                {
                    rowHeader.Cells[0].AddParagraph(languagPack["Report.Item.Name"]);
                    rowHeader.Cells[1].AddParagraph(languagPack["Report.Item.Quantity"]);
                    rowHeader.Cells[2].AddParagraph(languagPack["Report.Item.Price"]);
                    rowHeader.Cells[3].AddParagraph(languagPack["Report.Item.Total"]);
                }
                tblItems.Rows.Add(rowHeader);

                foreach(var i in order.Items)
                {
                    var rowItem = new Row();
                    {
                        var pCell0 = rowItem.Cells[0].AddParagraph();
                        {
                            var salesItem = uow.Execute(new GetSalesItemBySKU
                            {
                                SKU = i.SKU
                            }).Result;
                            var catItem = salesItem != null
                                ? salesItem.CatalogItem
                                : null;
                            var t_catItem = catItem != null
                                ? catItem.Translation(localization.Language.EntityID)
                                : null;
                            pCell0.AddText(t_catItem != null ? t_catItem.Name : i.SKU);
                        }
                        rowItem.Cells[1].Format.Alignment = ParagraphAlignment.Center;
                        var pCell1 = rowItem.Cells[1].AddParagraph();
                        {
                            pCell1.AddText(numFmt.Convert(i.Quantity));
                        }
                        rowItem.Cells[2].Format.Alignment = ParagraphAlignment.Center;
                        var pCell2 = rowItem.Cells[2].AddParagraph();
                        {
                            pCell2.AddFmtText(priceFmt, numFmt.Convert(i.Price));
                        }
                        rowItem.Cells[3].Format.Alignment = ParagraphAlignment.Right;
                        var pCell3 = rowItem.Cells[3].AddParagraph();
                        {
                            pCell3.AddText(languagPack["Report.Item.TaxAmount"]);
                            pCell3.AddFmtText(priceFmt, numFmt.Convert(i.TaxAmount));
                            pCell3.AddLineBreak();
                            pCell3.AddText(languagPack["Report.Item.DiscountAmount"]);
                            pCell3.AddFmtText(priceFmt, numFmt.Convert(i.DiscountAmount));
                            pCell3.AddLineBreak();
                            pCell3.AddText(languagPack["Report.Item.Subtotal"]);
                            pCell3.AddFmtText(priceFmt, numFmt.Convert(i.Subtotal));
                            pCell3.AddLineBreak();
                            pCell3.AddLineBreak();
                            pCell3.AddFmtText(TextFormat.Bold, priceFmt, numFmt.Convert(i.Total));
                        }
                    }
                    tblItems.Rows.Add(rowItem);
                }
            }
            sec.Add(tblItems);

            #endregion

            #region Comments

            var comments = order.Comments.Where(x => x.Flags.HasFlag(OrderCommentFlags.Public));
            if(comments.Any())
            {
                sec.AddPageBreak();
                var tblComments = new Table
                {
                    Borders =
                    {
                        Color = PDFHelper.COLOR_BLACK,
                        Width = Unit.FromCentimeter(0.01),
                        Style = BorderStyle.Single
                    },
                    TopPadding = Unit.FromCentimeter(0.05),
                    BottomPadding = Unit.FromCentimeter(0.05)
                };
                {
                    tblComments.AddColumn(Unit.FromCentimeter(4));
                    tblComments.AddColumn(Unit.FromCentimeter(12));

                    var rowTitle = new Row
                    {
                        HeadingFormat = true,
                        Format =
                        {
                            Font =
                            {
                                Bold = true
                            },
                            Alignment = ParagraphAlignment.Center
                        }
                    };
                    {
                        var cell0 = rowTitle.Cells[0];
                        cell0.MergeRight = 1;
                        cell0.AddParagraph(languagPack["Report.Order.Comments"]);
                    }
                    tblComments.Rows.Add(rowTitle);

                    foreach(var i in comments.OrderBy(x => x.CreatedOn))
                    {
                        var rowComment = new Row();
                        {
                            rowComment.Cells[0].AddParagraph(i.CreatedOn.ToLocal(utcOffset).ToStringByFmt(dtFmt));
                            rowComment.Cells[0].Format.Alignment = ParagraphAlignment.Center;
                            rowComment.Cells[1].AddParagraph(i.Text);
                        }
                        tblComments.Rows.Add(rowComment);
                    }
                }
                sec.Add(tblComments);
            }

            #endregion

            #region Footer

            var pFooter = new Paragraph
            {
                Format =
                {
                    Font =
                    {
                        Size = Unit.FromPoint(8)
                    }
                }
            };
            {
                pFooter.AddFmtText(languagPack["Report.Footer"], dtNow.Year, dtNow.ToLocal(utcOffset).ToStringByFmt(dtFmt));
            }
            sec.Footers.Primary.Add(pFooter);

            #endregion

            #endregion

            var renderer = new PdfDocumentRenderer(true, PdfFontEmbedding.Always)
            {
                Document = doc
            };
            renderer.RenderDocument();
            renderer.Save(OutStream, false);
        }

        #endregion
    }

    public class InvoicePdfReport : ReportOperation
    {
        #region Properties

        public override string MimeType
        {
            get
            {
                return "application/pdf";
            }
        }

        #endregion

        #region Utilities

        protected override Err Validate(IUnitOfWork uow)
        {
            if(Properties == null)
                return Err.Of(this).NotValid("Properties");
            if(!Properties.ContainsKey("invoiceID"))
                return Err.Of(this).NotSpecified("invoiceID");
            return base.Validate(uow);
        }

        protected override void Report(IUnitOfWork uow)
        {
            int invoiceID = Properties["invoiceID"].ParseAs<Int32>();
            var invoice = uow.Execute(new GetInvoice
            {
                ThrowsException = true,
                EntityID = invoiceID
            }).Result;
            var order = invoice.Order;
            var customer = order.Customer;
            var customerAcc = customer.Account;
            var localization = customerAcc.LocalizationProfile;
            var sysLocalization = uow.Execute(new GetLocalizationProfileByCode
            {
                ThrowsException = true,
                Code = uow.Execute(new GetConfigParamValueByKey
                {
                    Key = Par.In("Core").Of<LocalizationProfileEntity>().Name("System")
                }).Result
            }).Result;

            string locale = Properties.ContainsKey("locale")
                ? Properties["locale"]
                : String.Empty;
            if(!String.IsNullOrWhiteSpace(locale))
            {
                var tmp = uow.Execute(new GetLocalizationProfileByCode
                {
                    ThrowsException = true,
                    Code = locale
                }).Result;
                if(tmp != null)
                    localization = tmp;
            }

            var languagPack = uow.Execute(new GetLanguagePackContentByCode
            {
                Code = "PdfInvoice",
                LanguageID = localization.Language.EntityID
            }).Result;
            if(languagPack == null)
                throw Err.Of(this).NotFound("LanguagePack").Ex();

            int utcOffset = localization.TimeZone.UtcOffset;
            string dtFmt = localization.Country.DateTimeFormat;
            var priceFmt = sysLocalization.Currency.PriceFormat;
            var numFmt = localization.Country.NumericFormat;
            var dtNow = DateTime.UtcNow;

            var doc = new Document
            {
                Info =
                {
                    Title = String.Format(languagPack["Report.Title"], invoice.EntityID, invoice.Guid),
                    Author = languagPack["Report.Author"],
                    Comment = languagPack["Report.Comment"],
                    Subject = languagPack["Report.Subject"]
                }
            };
            var sec = doc.AddSection();

            #region PDF

            #region Title

            sec.AddParagraph().AddText(TextFormat.Bold, doc.Info.Title);
            sec.AddParagraph();
            sec.AddParagraph();

            #endregion

            #region Head

            var tblTop = new Table
            {
                Borders =
                {
                    Width = Unit.Zero,
                },
                Format =
                {
                    Font =
                    {
                        Size = Unit.FromPoint(9)
                    }
                }
            };
            {
                tblTop.AddColumn(Unit.FromCentimeter(8));
                tblTop.AddColumn(Unit.FromCentimeter(8));

                var row = new Row();
                {
                    var cell0 = row.Cells[0];
                    {
                        var p = new Paragraph();
                        {
                            p.AddFmtText(TextFormat.Italic, languagPack["Report.Order.Identifier"], order.EntityID, order.Guid);
                            p.AddLineBreak();
                            p.AddFmtText(TextFormat.Italic, languagPack["Report.Order.CreatedOn"], order.CreatedOn.ToLocal(utcOffset).ToStringByFmt(dtFmt));
                            p.AddLineBreak();
                            p.AddLineBreak();
                            p.AddText(TextFormat.Bold, languagPack["Report.Order.Status"]);
                            p.AddText(FlagsHelper.G1_Flags(order.Flags).ToString());
                            p.AddLineBreak();
                            p.AddText(TextFormat.Bold, languagPack["Report.Order.Total"]);
                            p.AddFmtText(priceFmt, numFmt.Convert(order.Total));
                        }
                        cell0.Add(p);
                    }
                    var cell1 = row.Cells[1];
                    {
                        var p = new Paragraph
                        {
                            Format =
                            {
                                Alignment = ParagraphAlignment.Right
                            }
                        };
                        {
                            p.AddFmtText(TextFormat.Italic, languagPack["Report.Invoice.Identifier"], invoice.EntityID, invoice.Guid);
                            p.AddLineBreak();
                            p.AddFmtText(TextFormat.Italic, languagPack["Report.Invoice.IssuedOn"], invoice.IssuedOn.ToLocal(utcOffset).ToStringByFmt(dtFmt));
                            p.AddLineBreak();
                            p.AddLineBreak();
                            p.AddText(TextFormat.Bold, languagPack["Report.Invoice.Status"]);
                            p.AddText(FlagsHelper.G1_Flags(invoice.Flags).ToString());
                            p.AddLineBreak();
                            p.AddText(TextFormat.Bold, languagPack["Report.Invoice.Total"]);
                            p.AddFmtText(priceFmt, numFmt.Convert(invoice.Total));
                            p.AddLineBreak();
                            p.AddLineBreak();
                            p.AddText(TextFormat.Bold, languagPack["Report.Invoice.RefundAmount"]);
                            p.AddFmtText(priceFmt, numFmt.Convert(invoice.RefundAmount));
                            p.AddLineBreak();
                            p.AddText(TextFormat.Bold, languagPack["Report.Invoice.PaidAmount"]);
                            p.AddFmtText(priceFmt, numFmt.Convert(invoice.PaidAmount));
                        }
                        cell1.Add(p);
                    }
                }
                tblTop.Rows.Add(row);
                sec.AddParagraph();
            }
            sec.Add(tblTop);
            sec.AddParagraph();

            #endregion

            #region From/To

            var tblAddr = new Table
            {
                Borders =
                {
                    Color = PDFHelper.COLOR_BLACK,
                    Width = Unit.FromCentimeter(0.01),
                    Style = BorderStyle.Single,
                },
                TopPadding = Unit.FromCentimeter(0.05),
                BottomPadding = Unit.FromCentimeter(0.05)
            };
            {
                tblAddr.AddColumn(Unit.FromCentimeter(8));
                tblAddr.AddColumn(Unit.FromCentimeter(8));

                var rowHeader = new Row
                {
                    HeadingFormat = true,
                    Format =
                    {
                        Font =
                        {
                            Bold = true
                        },
                        Alignment = ParagraphAlignment.Left
                    }
                };
                {
                    rowHeader.Cells[0].AddParagraph().AddFmtText(languagPack["Report.Order.BillingAddress"], order.BillingAddress.ContactName);
                    rowHeader.Cells[1].AddParagraph().AddFmtText(languagPack["Report.Order.SellerAddress"], order.SellerAddress.EntityName);
                }
                tblAddr.Rows.Add(rowHeader);

                var row = new Row();
                {
                    var cell0 = row.Cells[0];
                    {
                        var p = new Paragraph();
                        {
                            var addr = order.BillingAddress;
                            p.AddText(addr.ContactName);
                            p.AddLineBreak();
                            p.AddFmtText("{0} {1}", addr.Address1, addr.Address2);
                            p.AddLineBreak();
                            p.AddFmtText("{0}, {1} {2}", addr.City, addr.Region.Name, addr.PostalCode);
                            p.AddLineBreak();
                            p.AddText(addr.Country.Name);
                            p.AddLineBreak();
                            if(!String.IsNullOrWhiteSpace(addr.PhoneNumber))
                            {
                                p.AddFmtText("T: {0}", addr.PhoneNumber);
                                p.AddLineBreak();
                            }
                            if(!String.IsNullOrWhiteSpace(addr.FaxNumber))
                            {
                                p.AddFmtText("F: {0}", addr.FaxNumber);
                                p.AddLineBreak();
                            }
                            p.AddFmtText("@: {0}", addr.Email);
                        }
                        cell0.Add(p);
                    }
                    var cell1 = row.Cells[1];
                    {
                        var p = new Paragraph();
                        {
                            var addr = order.SellerAddress;
                            p.AddText(addr.ContactName);
                            p.AddLineBreak();
                            p.AddFmtText("{0} {1}", addr.Address1, addr.Address2);
                            p.AddLineBreak();
                            p.AddFmtText("{0}, {1} {2}", addr.City, addr.Region.Name, addr.PostalCode);
                            p.AddLineBreak();
                            p.AddText(addr.Country.Name);
                            p.AddLineBreak();
                            if(!String.IsNullOrWhiteSpace(addr.PhoneNumber))
                            {
                                p.AddFmtText("T: {0}", addr.PhoneNumber);
                                p.AddLineBreak();
                            }
                            if(!String.IsNullOrWhiteSpace(addr.FaxNumber))
                            {
                                p.AddFmtText("F: {0}", addr.FaxNumber);
                                p.AddLineBreak();
                            }
                            if(!String.IsNullOrWhiteSpace(addr.Website))
                            {
                                p.AddFmtText("W: {0}", addr.Website);
                                p.AddLineBreak();
                            }
                            p.AddFmtText("@: {0}", addr.Email);
                        }
                        cell1.Add(p);
                    }
                }
                tblAddr.Rows.Add(row);
            }
            sec.Add(tblAddr);

            #endregion

            #region Footer

            var pFooter = new Paragraph
            {
                Format =
                {
                    Font =
                    {
                        Size = Unit.FromPoint(8)
                    }
                }
            };
            {
                pFooter.AddFmtText(languagPack["Report.Footer"], dtNow.Year, dtNow.ToLocal(utcOffset).ToStringByFmt(dtFmt));
            }
            sec.Footers.Primary.Add(pFooter);

            #endregion

            #endregion

            var renderer = new PdfDocumentRenderer(true, PdfFontEmbedding.Always)
            {
                Document = doc
            };
            renderer.RenderDocument();
            renderer.Save(OutStream, false);
        }

        #endregion
    }

    public class PaymentPdfReport : ReportOperation
    {
        #region Properties

        public override string MimeType
        {
            get
            {
                return "application/pdf";
            }
        }

        #endregion

        #region Utilities

        protected override Err Validate(IUnitOfWork uow)
        {
            if(Properties == null)
                return Err.Of(this).NotValid("Properties");
            if(!Properties.ContainsKey("paymentID"))
                return Err.Of(this).NotSpecified("paymentID");
            return base.Validate(uow);
        }

        protected override void Report(IUnitOfWork uow)
        {
            int paymentID = Properties["paymentID"].ParseAs(0);
            var payment = uow.Execute(new GetPayment
            {
                ThrowsException = true,
                EntityID = paymentID
            }).Result;
            var invoice = payment.Invoice;
            var order = invoice.Order;
            var customer = payment.Customer;
            var customerAcc = customer.Account;
            var localization = customerAcc.LocalizationProfile;
            var sysLocalization = uow.Execute(new GetLocalizationProfileByCode
            {
                ThrowsException = true,
                Code = uow.Execute(new GetConfigParamValueByKey
                {
                    Key = Par.In("Core").Of<LocalizationProfileEntity>().Name("System")
                }).Result
            }).Result;

            string locale = Properties.ContainsKey("locale")
                ? Properties["locale"]
                : String.Empty;
            if(!String.IsNullOrWhiteSpace(locale))
            {
                var tmp = uow.Execute(new GetLocalizationProfileByCode
                {
                    ThrowsException = true,
                    Code = locale
                }).Result;
                if(tmp != null)
                    localization = tmp;
            }

            var languagPack = uow.Execute(new GetLanguagePackContentByCode
            {
                Code = "PdfPayment",
                LanguageID = localization.Language.EntityID
            }).Result;
            if(languagPack == null)
                throw Err.Of(this).NotFound("LanguagePack").Ex();

            int utcOffset = localization.TimeZone.UtcOffset;
            string dtFmt = localization.Country.DateTimeFormat;
            var priceFmt = sysLocalization.Currency.PriceFormat;
            var numFmt = localization.Country.NumericFormat;
            var dtNow = DateTime.UtcNow;

            var doc = new Document
            {
                Info =
                {
                    Title = String.Format(languagPack["Report.Title"], payment.EntityID, payment.Guid),
                    Author = languagPack["Report.Author"],
                    Comment = languagPack["Report.Comment"],
                    Subject = languagPack["Report.Subject"]
                }
            };
            var sec = doc.AddSection();

            #region PDF

            #region Title

            sec.AddParagraph().AddText(TextFormat.Bold, doc.Info.Title);
            sec.AddParagraph();
            sec.AddParagraph();

            #endregion

            #region Head

            var tblTop = new Table
            {
                Borders =
                {
                    Width = Unit.Zero,
                },
                Format =
                {
                    Font =
                    {
                        Size = Unit.FromPoint(9)
                    }
                }
            };
            {
                tblTop.AddColumn(Unit.FromCentimeter(8));
                tblTop.AddColumn(Unit.FromCentimeter(8));

                var row = new Row();
                {
                    var cell0 = row.Cells[0];
                    {
                        var p = new Paragraph();
                        {
                            p.AddFmtText(TextFormat.Italic, languagPack["Report.Invoice.Identifier"], invoice.EntityID, invoice.Guid);
                            p.AddLineBreak();
                            p.AddFmtText(TextFormat.Italic, languagPack["Report.Invoice.IssuedOn"], invoice.IssuedOn.ToLocal(utcOffset).ToStringByFmt(dtFmt));
                            p.AddLineBreak();
                            p.AddLineBreak();
                            p.AddText(TextFormat.Bold, languagPack["Report.Invoice.Status"]);
                            p.AddText(FlagsHelper.G1_Flags(invoice.Flags).ToString());
                            p.AddLineBreak();
                            p.AddText(TextFormat.Bold, languagPack["Report.Invoice.Total"]);
                            p.AddFmtText(priceFmt, numFmt.Convert(invoice.Total));
                        }
                        cell0.Add(p);
                    }
                    var cell1 = row.Cells[1];
                    {
                        var p = new Paragraph
                        {
                            Format =
                            {
                                Alignment = ParagraphAlignment.Right
                            }
                        };
                        {
                            p.AddFmtText(TextFormat.Italic, languagPack["Report.Payment.Identifier"], payment.EntityID, payment.Guid);
                            p.AddLineBreak();
                            p.AddFmtText(TextFormat.Italic, languagPack["Report.Payment.CreatedOn"], payment.CreatedOn.ToLocal(utcOffset).ToStringByFmt(dtFmt));
                            p.AddLineBreak();
                            p.AddLineBreak();
                            p.AddText(TextFormat.Bold, languagPack["Report.Payment.Status"]);
                            p.AddText(FlagsHelper.G1_Flags(payment.Flags).ToString());
                            p.AddLineBreak();
                            p.AddText(TextFormat.Bold, languagPack["Report.Payment.Amount"]);
                            p.AddFmtText(priceFmt, numFmt.Convert(payment.Amount));
                            p.AddLineBreak();
                            p.AddText(TextFormat.Bold, languagPack["Report.Payment.HandlingFee"]);
                            p.AddFmtText(priceFmt, numFmt.Convert(payment.HandlingFee));
                        }
                        cell1.Add(p);
                    }
                }
                tblTop.Rows.Add(row);
                sec.AddParagraph();
            }
            sec.Add(tblTop);
            sec.AddParagraph();

            #endregion

            #region From/To/Paid by

            var tblAddr = new Table
            {
                Borders =
                {
                    Color = PDFHelper.COLOR_BLACK,
                    Width = Unit.FromCentimeter(0.01),
                    Style = BorderStyle.Single,
                },
                TopPadding = Unit.FromCentimeter(0.05),
                BottomPadding = Unit.FromCentimeter(0.05)
            };
            {
                tblAddr.AddColumn(Unit.FromCentimeter(8));
                tblAddr.AddColumn(Unit.FromCentimeter(8));

                var rowHeader = new Row
                {
                    HeadingFormat = true,
                    Format =
                    {
                        Font =
                        {
                            Bold = true
                        },
                        Alignment = ParagraphAlignment.Left
                    }
                };
                {
                    rowHeader.Cells[0].AddParagraph().AddFmtText(languagPack["Report.Order.BillingAddress"], order.BillingAddress.ContactName);
                    rowHeader.Cells[1].AddParagraph().AddFmtText(languagPack["Report.Order.SellerAddress"], order.SellerAddress.EntityName);
                }
                tblAddr.Rows.Add(rowHeader);

                var row = new Row();
                {
                    var cell0 = row.Cells[0];
                    {
                        var p = new Paragraph();
                        {
                            var addr = order.BillingAddress;
                            p.AddText(addr.ContactName);
                            p.AddLineBreak();
                            p.AddFmtText("{0} {1}", addr.Address1, addr.Address2);
                            p.AddLineBreak();
                            p.AddFmtText("{0}, {1} {2}", addr.City, addr.Region.Name, addr.PostalCode);
                            p.AddLineBreak();
                            p.AddText(addr.Country.Name);
                            p.AddLineBreak();
                            if(!String.IsNullOrWhiteSpace(addr.PhoneNumber))
                            {
                                p.AddFmtText("T: {0}", addr.PhoneNumber);
                                p.AddLineBreak();
                            }
                            if(!String.IsNullOrWhiteSpace(addr.FaxNumber))
                            {
                                p.AddFmtText("F: {0}", addr.FaxNumber);
                                p.AddLineBreak();
                            }
                            p.AddFmtText("@: {0}", addr.Email);
                        }
                        cell0.Add(p);
                    }
                    var cell1 = row.Cells[1];
                    {
                        var p = new Paragraph();
                        {
                            var addr = order.SellerAddress;
                            p.AddText(addr.ContactName);
                            p.AddLineBreak();
                            p.AddFmtText("{0} {1}", addr.Address1, addr.Address2);
                            p.AddLineBreak();
                            p.AddFmtText("{0}, {1} {2}", addr.City, addr.Region.Name, addr.PostalCode);
                            p.AddLineBreak();
                            p.AddText(addr.Country.Name);
                            p.AddLineBreak();
                            if(!String.IsNullOrWhiteSpace(addr.PhoneNumber))
                            {
                                p.AddFmtText("T: {0}", addr.PhoneNumber);
                                p.AddLineBreak();
                            }
                            if(!String.IsNullOrWhiteSpace(addr.FaxNumber))
                            {
                                p.AddFmtText("F: {0}", addr.FaxNumber);
                                p.AddLineBreak();
                            }
                            if(!String.IsNullOrWhiteSpace(addr.Website))
                            {
                                p.AddFmtText("W: {0}", addr.Website);
                                p.AddLineBreak();
                            }
                            p.AddFmtText("@: {0}", addr.Email);
                        }
                        cell1.Add(p);
                    }
                }
                tblAddr.Rows.Add(row);
            }
            sec.Add(tblAddr);

            var pPaidBy = new Paragraph
            {
                Format =
                {
                    Alignment = ParagraphAlignment.Right
                }
            };
            {
                pPaidBy.AddLineBreak();
                pPaidBy.AddLineBreak();
                pPaidBy.AddText(TextFormat.Bold, languagPack["Report.Payment.Customer"]);
                pPaidBy.AddText(payment.Customer.Account.Email);
            }
            sec.Add(pPaidBy);

            #endregion

            #region Footer

            var pFooter = new Paragraph
            {
                Format =
                {
                    Font =
                    {
                        Size = Unit.FromPoint(8)
                    }
                }
            };
            {
                pFooter.AddFmtText(languagPack["Report.Footer"], dtNow.Year, dtNow.ToLocal(utcOffset).ToStringByFmt(dtFmt));
            }
            sec.Footers.Primary.Add(pFooter);

            #endregion

            #endregion

            var renderer = new PdfDocumentRenderer(true, PdfFontEmbedding.Always)
            {
                Document = doc
            };
            renderer.RenderDocument();
            renderer.Save(OutStream, false);
        }

        #endregion
    }
}
